package com.fishery.processing.util;

import com.fishery.entity.GlobalException;
import com.fishery.entity.StatusCode;
import com.fishery.processing.dao.*;
import com.fishery.processing.entity.*;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @author run
 * @since 2021/1/19 15:32
 */
@Component
public class UpdateProxy{

    @Autowired
    private FactoryDao factoryDao;

    @Autowired
    private ProductDao productDao;

    @Autowired
    private CraftDao craftDao;

    @Autowired
    private InputDao inputDao;

    @Autowired
    private QualificationDao qualificationDao;

    private Object target;

    public UpdateProxy bind(Object target){
        this.target = target;
        return this;
    }

    public Object getProxyInstance(){
        return Proxy.newProxyInstance(target.getClass().getClassLoader()
                , getInterfaces(target.getClass()).toArray(new Class[0])
                , (obj,method,objects)->{
                    //获取修改的类型
                    Object change = objects[0];
                    Class<?> aClass = change.getClass();
                    Field[] fields;
                    Object origin;
                    if (aClass.equals(Factory.class)){
                        fields = Factory.class.getDeclaredFields();
                        origin = factoryDao.findFactoryById(((Factory)change).getId());
                    }else if (aClass.equals(Product.class)){
                        fields = Product.class.getDeclaredFields();
                        origin = productDao.findProductById(((Product)change).getId());
                    }else if (aClass.equals(Craft.class)){
                        fields = Craft.class.getDeclaredFields();
                        origin = craftDao.findCraftById(((Craft)change).getId());
                    }else if (aClass.equals(Input.class)){
                        fields = Input.class.getDeclaredFields();
                        origin = inputDao.findInputById(((Input)change).getId());
                    }else {
                        fields = Qualification.class.getDeclaredFields();
                        origin = qualificationDao.findQualificationById(((Qualification)change).getId());
                    }
                    if (origin == null){
                        throw new GlobalException(StatusCode.ERROR,"所修改的对象不存在");
                    }
                    for (Field field : fields) {
                        //将private属性设置可访问
                        field.setAccessible(true);
                        if (field.isAnnotationPresent(Unchangeable.class)){
                            if (!field.get(change).equals(field.get(origin))){
                                throw new GlobalException(StatusCode.ERROR,getErrorMessage(field));
                            }
                        }
                    }
                    Object result = method.invoke(target,objects);
                    return result;
                });
    }

    //生成异常错误信息
    private static String getErrorMessage(Field field){
        String message = field.getAnnotation(Unchangeable.class).message();
        if (!message.isEmpty()){
            return message;
        }
        return field.getName() + (field.isAnnotationPresent(ApiModelProperty.class)
                ? ("（" + field.getAnnotation(ApiModelProperty.class).value() + "）") : "")
                + "为不可变属性，无法修改";
    }

    //获取类的所有接口，包括间接实现的
    private static List<Class<?>> getInterfaces(Class<?> implClass){
        if (implClass.equals(Object.class)){
            return Collections.emptyList();
        }
        List<Class<?>> classes = new ArrayList<>(Arrays.asList(implClass.getInterfaces()));
        classes.addAll(getInterfaces(implClass.getSuperclass()));
        return classes;
    }
}
